package com.hzit.pay.center.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.hzit.pay.center.exception.BizException;
import com.hzit.pay.center.factory.PayStrategyFactory;
import com.hzit.pay.center.model.MchInfo;
import com.hzit.pay.center.model.MchPayChannelInfo;
import com.hzit.pay.center.model.PaySerialNoInfo;
import com.hzit.pay.center.service.IPaySerialNoService;
import com.hzit.pay.center.service.strategy.IPaymentService;
import com.hzit.pay.center.service.strategy.impl.AlipayPagePayServiceImpl;
import com.hzit.pay.center.utils.AlipayUtil;
import com.pay.center.common.enums.PayChannelEnum;
import com.pay.center.common.enums.PayMethodEnum;
import com.pay.center.common.enums.PayStatusEnum;
import com.pay.center.common.req.PayCallBackData;
import com.pay.center.common.req.PaymentQueryReq;
import com.pay.center.common.req.PaymentReq;
import com.hzit.pay.center.service.IMchService;
import com.hzit.pay.center.service.IPayChannelService;
import com.hzit.pay.center.service.IPayService;
import com.pay.center.common.req.QueryPayMethodReq;
import com.pay.center.common.resp.PayMethodData;
import com.pay.center.common.resp.RespPayData;
import com.pay.center.common.resp.Response;
import com.pay.center.common.utils.PayDigestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.List;

@Service
public class PayServiceImpl implements IPayService {

    @Autowired
    private IPayChannelService payChannelService;

    @Autowired
    private IMchService mchService;

    @Autowired
    private IPaySerialNoService paySerialNoService;

    @Autowired
    private AlipayUtil alipayUtil;


    private Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

    private static final String WAIT_BUYER_PAY = "WAIT_BUYER_PAY";
    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";

    private static final String TRADE_FINISHED = "TRADE_FINISHED";
    private static final String TRADE_CLOSED = "TRADE_CLOSED";



    @Override
    public List<PayMethodData> queryPayMethodList(QueryPayMethodReq queryPayMethodReq) throws BizException {

        //1.签名验证
        MchInfo mchInfo =  mchService.queryMchInfoById(queryPayMethodReq.getMchId());
        if (ObjectUtils.isEmpty(mchInfo)){
            logger.info("商户号：{}，不存在",queryPayMethodReq.getMchId());
            throw new BizException("商户id不存在");
        }

        if (!"0".equals(mchInfo.getStaus())){
            logger.info("商户号：{}，状态不可用",queryPayMethodReq.getMchId());
            throw new BizException("商户状态不可用");
        }

        String reqKey = mchInfo.getReqKey();

        //业务系统请求的签名
        String sign = queryPayMethodReq.getSign();

        //支付中心再次生成的
        String newSign = "";

        if (!sign.equals(newSign)){
            logger.info("商户号：{}，请求非法",queryPayMethodReq.getMchId());
            throw new BizException("请求非法");
        }


        List<PayMethodData>  payMethodDataList = payChannelService.queryByMchId(queryPayMethodReq.getMchId());
        return payMethodDataList;
    }


    /**
     * 执行支付
     * @param paymentReq
     * @throws BizException
     */
    @Override
    public Response<RespPayData> doPay(PaymentReq paymentReq) throws BizException {


        MchInfo mchInfo = mchService.queryMchInfoById(paymentReq.getMchId());
        if (ObjectUtils.isEmpty(mchInfo)){
            logger.info("商户id：{}，不存在",paymentReq.getOrderId());
            throw new BizException("商户id不存在");
        }

        if (!"0".equals(mchInfo.getStaus())){
            logger.info("商户号：{}，状态不可用",paymentReq.getMchId());
            throw new BizException("商户状态不可用");
        }

        MchPayChannelInfo mchPayChannelInfo = payChannelService.queryByMchIdAndPayMethod(paymentReq.getMchId(),
                paymentReq.getPayChannel(),paymentReq.getPayMethod());

        if (ObjectUtils.isEmpty(mchPayChannelInfo)){
            logger.info("商户号：{}，不支持该支付方式",paymentReq.getMchId());
            throw new BizException("不支持该支付方式");
        }

        if (!"0".equals(mchPayChannelInfo.getStatus())){
            logger.info("商户号：{}，支付渠道：{}，支付方式：{}状态不可用",paymentReq.getMchId()
                    ,paymentReq.getPayChannel(),paymentReq.getPayMethod());
            throw new BizException("支付渠道状态不可用");
        }


        //对象转map
        JSONObject jsonObject = (JSONObject)JSONObject.toJSON(paymentReq);

        //2.验证签名.
        String newSign = PayDigestUtil.getSign(jsonObject,mchInfo.getReqKey(),"sign");

//      String newSign = PayDigestUtil.getSign(paymentReq,mchInfo.getReqKey());
//        if (!paymentReq.getSign().equals(newSign)){
//            logger.info("订单号：{}，请求非法",paymentReq.getOrderId());
//            throw new BizException("该订单请求非法");
//        }

        //生成流水，先查询在插入。 //TODO.防止一个订单生成多笔待支付的流水
        List<PaySerialNoInfo> paySerialNoInfoList = paySerialNoService.queryByOrderId(paymentReq.getOrderId());

        if (!CollectionUtils.isEmpty(paySerialNoInfoList)){
            logger.info("订单号：{}，请求非法",paymentReq.getOrderId());
            throw new BizException("该订单正在支付");
        }

        PaySerialNoInfo paySerialNoInfo = paySerialNoService.createPaySerialNo(paymentReq);


        //根据类型创建不同对象
        String payMethod = paymentReq.getPayMethod();

        IPaymentService paymentService = PayStrategyFactory.getPayStrategy(payMethod);
        if (ObjectUtils.isEmpty(paymentService)){
            logger.info("订单号：{}，暂不支持该支付方式",paymentReq.getOrderId());
            throw new BizException("暂不支持该支付方式");
        }

        Response<RespPayData> response = paymentService.payment(paySerialNoInfo,mchInfo.getRespKey());

        //5.获取支付返回结果
        return response;

    }

    @Override
    public Response<PayCallBackData> query(PaymentQueryReq queryReq) throws BizException {
        //各种判断 TODO


        //根据订单号或者流水号查询。
        PaySerialNoInfo paySerialNoInfo = paySerialNoService.queryBySerialNo(queryReq.getPaySerialNo());

        if (ObjectUtils.isEmpty(paySerialNoInfo)){
            //封装流水号不存在
            return null;
        }

       if (PayStatusEnum.FAIL.getCode().equals(paySerialNoInfo.getPayStatus())
               || PayStatusEnum.SUCCESS.getCode().equals(paySerialNoInfo.getPayStatus())){

            //封装支付成功或者失败
            return null;
        }

       //调用接口查询
        if (PayChannelEnum.ALIPAY.getCode().equals(paySerialNoInfo.getPayChannel())){

            try {
                //调用支付宝查询接口
                AlipayTradeQueryResponse response = alipayUtil.alipayPayQuery(paySerialNoInfo);

                //先判断AlipayTradeQueryResponse 的状态是否为成功，code sub_code

                String tradeStatus = response.getTradeStatus();


                if(WAIT_BUYER_PAY.equals(tradeStatus)){
                    //返回待支付的给业务系统


                }else if(TRADE_SUCCESS.equals(tradeStatus) || TRADE_FINISHED.equals(tradeStatus)){
                    //更新数据库，流水状态为成功

                    //封装支付成功对象返回


                }else if(TRADE_CLOSED.equals(tradeStatus)){
                    //更新数据库，流水状态为失败

                    //封装支付成功对象返回

                }



            } catch (AlipayApiException e) {
                e.printStackTrace();
                //TODO
            }


        }else if(PayChannelEnum.WECHAT_PAY.getCode().equals(paySerialNoInfo.getPayChannel())){

            //调用微信的查询接口

        }




        return null;
    }

    @Override
    public List<PaySerialNoInfo> queryUnConfirmedList() throws BizException {

        List<PaySerialNoInfo>  list= paySerialNoService.queryUnPayList();

//        List list = (List) response.getData();

        if (CollectionUtils.isEmpty(list)){
            //打印没有数据


        }


        //list很大，可以考虑线程池处理：更合理利用cpu
        for (int i=0;i<list.size();i++){

            //2.直接调用支付宝交易查询接口 同步处理。 并行处理任务，创建的线程要有返回值。future模式
            // 线程安全问题。乐观锁
        }

        //3.更新数据库状态


        return list;
    }

    @Override
    public void payClose() throws BizException {

        //1.查询流水表交易的状态。

        //2.对未支付或者支付总的允许发起交易关闭


        //3.根据传过来得支付渠道，调用对的支付公司交易关闭接口

        //4.根据状态更新流水，分钟Reponse返回给业务系统



    }
}
